package cn.imatu.framework.model;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.imatu.framework.exception.BizException;
import com.alibaba.fastjson2.JSONObject;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 分页参数, 需要分页查询的继承该类
 * @author shenguangyang
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(name = "分页参数")
public class BasePageReq extends BaseQuery implements Serializable {
    private static final Integer PAGE_NUM = 1;
    private static final Integer PAGE_SIZE = 20;
    private static Set<String> KEYS;

    static {
        KEYS = JSONObject.from(new BasePageReq()).keySet();
    }

    @Schema(description = "页码，从 1 开始", example = "1")
    @NotNull(message = "页码不能为空")
    @Min(value = 1, message = "页码最小值为 1")
    protected Integer pageNum = PAGE_NUM;

    @Schema(description = "每页条数，最大值为 100", example = "10")
    @NotNull(message = "每页条数不能为空")
    @Min(value = 1, message = "每页条数最小值为 1")
    @Max(value = 1000, message = "每页条数最大值为 1000")
    protected Integer pageSize = PAGE_SIZE;

    @Schema(description = "排序的方向desc或者asc", example = "asc")
    protected String order = "asc";

    @Schema(description = "排序列", example = "asc")
    protected String orderByColumn;

    @Schema(description = "开始时间", example = "2023-06-08 11:00:00")
    protected String beginDate;

    @Schema(description = "结束时间", example = "2023-06-08 11:00:00")
    protected String endDate;

    public String getOrderBy() {
        if (StringUtils.isEmpty(orderByColumn)) {
            return "";
        }
        return humpToUnderline(orderByColumn) + " " + order;
    }

    /**
     * 驼峰转下划线命名 humpToUnderline
     */
    public static String humpToUnderline(String str) {
        String regex = "([A-Z])";
        Matcher matcher = Pattern.compile(regex).matcher(str);
        while (matcher.find()) {
            String target = matcher.group();
            str = str.replaceAll(target, "_" + target.toLowerCase());
        }
        return str;
    }

    private String getFormatBeginDate() {
        String tempBeginDate = this.beginDate;
        if (StrUtil.isNotEmpty(this.beginDate) && !this.beginDate.contains(" ")) {
            tempBeginDate = tempBeginDate + " 00:00:00";
        }
        return tempBeginDate;
    }

    private String getFormatEndDate() {
        String tempEndDate = this.endDate;
        if (StrUtil.isNotEmpty(this.endDate) && !this.endDate.contains(" ")) {
            tempEndDate = tempEndDate + " 23:59:59";
        }
        return tempEndDate;
    }

    @Schema(hidden = true)
    public LocalDateTime getBeginLocalDateTime() {
        DateTime parse = DateUtil.parse(this.getFormatBeginDate());
        return Optional.ofNullable(parse).map(DateTime::toLocalDateTime).orElse(null);
    }

    @Schema(hidden = true)
    public LocalDateTime getEndLocalDateTime() {
        DateTime parse = DateUtil.parse(this.getFormatEndDate());
        return Optional.ofNullable(parse).map(DateTime::toLocalDateTime).orElse(null);
    }

    @Schema(hidden = true)
    public Date getBeginJdkDate() {
        DateTime parse = DateUtil.parse(this.getFormatBeginDate());
        return Optional.ofNullable(parse).map(DateTime::toJdkDate).orElse(null);
    }

    @Schema(hidden = true)
    public Date getEndJdkDate() {
        DateTime parse = DateUtil.parse(this.getFormatBeginDate());
        return Optional.ofNullable(parse).map(DateTime::toJdkDate).orElse(null);
    }

    public void setOrder(String order) {
        // 兼容前端排序类型
        if ("ascending".equals(order)) {
            order = "asc";
        } else if ("descending".equals(order)) {
            order = "desc";
        }
        this.order = order;
    }

    @Override
    public void verifyIsAllNull() {
        JSONObject jsonObject = JSONObject.from(this);
        KEYS.forEach(jsonObject::remove);
        if (jsonObject.values().stream().allMatch(Objects::isNull)) {
            throw new BizException("查询条件不能全部为空");
        }
    }
}
